package cn.qiyu5522.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.qiyu5522.constant.SystemConsKeys;
import cn.qiyu5522.constant.SystemConstants;
import cn.qiyu5522.domain.VO.AdminUserInfoVO;
import cn.qiyu5522.domain.VO.MenuRouteVO;
import cn.qiyu5522.domain.VO.RoutersVo;
import cn.qiyu5522.domain.VO.UserInfoVO;
import cn.qiyu5522.domain.entity.LoginUser;
import cn.qiyu5522.domain.entity.Menu;
import cn.qiyu5522.domain.entity.ResponseResult;
import cn.qiyu5522.domain.entity.User;
import cn.qiyu5522.enums.AppHttpCodeEnum;
import cn.qiyu5522.handlers.exceptions.SystemException;
import cn.qiyu5522.service.*;
import cn.qiyu5522.utils.BeanCopyUtils;
import cn.qiyu5522.utils.JwtUtil;
import cn.qiyu5522.utils.RedisCache;
import cn.qiyu5522.utils.SecurityUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * ClassName: LoginServiceImpl
 * Package: cn.qiyu5522.service.impl
 * Description:
 *
 * @Author: Tonkey
 * @Create：2024/4/17-8:36
 * @Version: v1.0
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private RedisCache redisCache;

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    @Resource
    private MenuService menuService;

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private RoleMenuService roleMenuService;

    @Resource
    private AuthenticationManager authenticationManager;

    @Override
    public ResponseResult login(User user) {
        //  将未验证的用户信息，设置到 Authentication
        Authentication authentication = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authentication);
        // 判断登录用户是否认证通过
        if (ObjectUtil.isNull(authenticate)) {
            throw new SystemException(AppHttpCodeEnum.LOGIN_ERROR);
        }
        // 获取 UserId 生成 token
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getId().toString();
        String token = JwtUtil.createJWT(userId);
        // 把用户信息存入redis
        redisCache.setCacheObject(SystemConsKeys.BACK_USER_LOGIN + userId, loginUser, SystemConsKeys.REDIS_TTL);

        //把token封装 返回
        Map<String, String> map = new HashMap<>();
        map.put("token", token);

        // 把 User 转化成 UserInfoVO
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult getInfo() {
        //获取当前登录的用户
        User user = SecurityUtils.getUser();
        //根据用户id查询权限信息
        List<String> perms = menuService.selectPermsByUserId(user.getId());
        //根据用户id查询角色信息
        List<String> roleKeyList = roleService.selectRoleKeyByUserId(user.getId());
        //获取用户信息
        UserInfoVO userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVO.class);
        //封装数据返回
        AdminUserInfoVO adminUserInfoVo = new AdminUserInfoVO(perms, roleKeyList, userInfoVo);
        return ResponseResult.okResult(adminUserInfoVo);
    }

    @Override
    public ResponseResult getRouters() {
        User user = SecurityUtils.getUser();
        // 根据用户id 查询 拥有的菜单
        List<Menu> menus = menuService.selectMenusByUserId(user.getId());

        // Menu 转 MenuVO
        List<MenuRouteVO> menuRouteVOS = BeanCopyUtils.copyBeanList(menus, MenuRouteVO.class);

        // 构建菜单树
        // 返回的菜单树
        List<MenuRouteVO> menuTree = new ArrayList<>();
        // 1. 找出根节点菜单
        List<MenuRouteVO> rootMenus = menuRouteVOS.stream().filter(menu -> SystemConstants.ROOT_MENU.equals(menu.getParentId()))
                .collect(Collectors.toList());
        // 2. 递归设置子菜单
        rootMenus.forEach(menuRouteVO -> {
            menuRouteVO.setChildren(getChildren(menuRouteVO.getId(), menuRouteVOS));
            menuTree.add(menuRouteVO);
        });
        return ResponseResult.okResult(new RoutersVo(menuTree));
    }

    @Override
    public ResponseResult logout() {
        // 获取用户 id
        Long loginUserId = SecurityUtils.getLoginUserId();
        // 清空 redis 中 登录用户的 key
        boolean flag = redisCache.deleteObject(SystemConsKeys.BACK_USER_LOGIN+loginUserId);
        if(!flag){
            throw new RuntimeException(new cn.qiyu5522.domain.entity.SystemException(AppHttpCodeEnum.NEED_LOGIN));
        }
        return ResponseResult.okResult();
    }

    private List<MenuRouteVO> getChildren(Long parentId, List<MenuRouteVO> menuList) {
        // 获取子菜单
        List<MenuRouteVO> children = new ArrayList<>();
        for (MenuRouteVO menuRouteVO : menuList) {
            if (parentId.equals(menuRouteVO.getParentId())) {
                // 递归 设置子菜单
                menuRouteVO.setChildren(getChildren(menuRouteVO.getId(), menuList));
                children.add(menuRouteVO);
            }
        }
        return children;
    }
}
